#pragma once

#include <iostream>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/time.h>
#include <sys/resource.h>
#include "../com/util.hpp"
#include "../com/log.hpp"
namespace lh_runner
{
    using namespace lh_util;
    using namespace lh_log;
    class Runner
    {
        public:
        Runner() {}
        ~Runner() {}

    public:
        //cpu单位-秒  mem单位 KB
        static void SetRlimit(int cpu, int mem)
        {
            struct rlimit rl_cpu;
            rl_cpu.rlim_cur = cpu*1024;
            rl_cpu.rlim_max = RLIM_INFINITY;
            setrlimit(RLIMIT_CPU, &rl_cpu);

            struct rlimit rl_mem;
            rl_mem.rlim_cur = mem*1024;
            rl_mem.rlim_max = RLIM_INFINITY;
            setrlimit(RLIMIT_AS,&rl_mem);
        }
        /*Run返回值
         * -1
         * -2
         * 0
         * >0
         */
        static int Run(const std::string &file_name, int cpu_limit, int mem_limit)
        {
            std::string execut = PathUtil::Exe(file_name);
            std::string _in = PathUtil::In(file_name);
            std::string _out = PathUtil::Out(file_name);
            std::string _err = PathUtil::Err(file_name);
            int in_fd = open(_in.c_str(), O_CREAT | O_RDONLY, 0664);
            int out_fd = open(_out.c_str(), O_CREAT | O_WRONLY, 0664);
            int err_fd = open(_err.c_str(), O_CREAT | O_WRONLY, 0664);
            if (in_fd < 0 || out_fd < 0 || err_fd < 0)
            {
                LOG(ERROR) << "run error, 创建/打开文件失败" << "\n";
                return -1;
            }
            pid_t pid = fork();
            if (pid < 0)
            {
                close(in_fd);
                close(out_fd);
                close(err_fd);
                LOG(ERROR) << "run error, 创建子进程失败" << "\n";
                return -2;
            }
            else if (pid == 0)
            {
                // 子进程
                SetRlimit(cpu_limit, mem_limit);
                // 重定向
                dup2(in_fd, 0);
                dup2(out_fd, 1);
                dup2(err_fd, 2);
                // 程序替换
                execl(execut.c_str(), execut.c_str(), nullptr);
                exit(1);
            }
            else
            {
                close(in_fd);
                close(out_fd);
                close(err_fd);
                int status;
                waitpid(pid, &status, 0);
                LOG(INFO) << "run success, status : " << (status & 0x7f) << "\n";
                return status & 0x7f;
            }
        }
    };
}